#include "widget.h"
#include "ui_widget.h"
#include <QSerialPortInfo>
#include <QDebug>
#include <QMessageBox>
#include <QTimer>
#include <QFileDialog>
#include <QDateTime>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);      //让界面随着窗口变幻大小

    ui->btnSendContex->setEnabled(false);       //刚打开串口，发送按钮是失效的
    ui->checkBoxSendInTime->setEnabled(false);  //刚打开串口界面，定时发送选择框是失效的
    ui->checkBoxrevTime->setEnabled(false);  //刚打开串口界面，接收时间选择框是失效的


    serialPort = new QSerialPort(this);         //创建一个QSerialPort对象，将指针赋值给serialPort变量

    QTimer *getSysTimeTimer = new QTimer(this);     //创建一个QTimer对象，将指针赋值给getSysTimeTimer
    connect(getSysTimeTimer,SIGNAL(timeout()),this,SLOT(time_reflash()));
    getSysTimeTimer->start(100);       //启动定时器，每隔100毫秒触发一次timeout信号

    timer = new QTimer(this);                   //创建一个时间对象

    writeCntTotal = 0;
    readCntTotal = 0;


    connect(timer,&QTimer::timeout,this,[=](){
        on_btnSendContex_clicked();
    });         //连接信号与槽，到点就发送文本
    connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_SerialData_readyToRead);        //连接函数，当接收数据可读时

    ui->comboBox_boautrate->setCurrentIndex(6);         //将波特率索引值设置为6,方便选择
    ui->comboBox_databit->setCurrentIndex(3);           //将数据位索引值设置为3,方便选择


    QList<QSerialPortInfo> serialList= QSerialPortInfo::availablePorts();     //获取系统中可用的串口
    for(QSerialPortInfo serialInfo : serialList)        //遍历所有可用串口
    {
        qDebug() <<  serialInfo.portName();
        ui->comboBox_serialnum->addItem(serialInfo.portName());     //将serialInfo对象所代表的串口添加到UI中
    }

}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btncloseorOpen_clicked(bool checked)
{
    if(checked)
    {
        //1.选择端口号
        serialPort->setPortName(ui->comboBox_serialnum->currentText());     //获取串口，把串口显示到文本上
        //2.配置波特率
        serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());  //显示波特率，转整型
        //3.配置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt()));    //显示波特率，转整型
        //4.配置校验位
        switch (ui->comboBox_jiaoyan->currentText().toInt())       //用户选择校验位，并转为整型
        {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);       //无奇偶校验
            break;
        case 1:
            serialPort->setParity(QSerialPort::EvenParity);     //偶校验
            break;
        case 2:
            serialPort->setParity(QSerialPort::MarkParity);     //标记校验
            break;
        case 3:
            serialPort->setParity(QSerialPort::OddParity);      //奇校验
            break;
        case 4:
            serialPort->setParity(QSerialPort::SpaceParity);    //空格校验
            break;
        default:
            serialPort->setParity(QSerialPort::UnknownParity);  //未知校验
            break;
        }
        //5.配置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt()));      //显示停止位，转整型
        //6.流控
        if(ui->comboBox_fluidCon->currentText() == "None")      //用户选择了None
        {
            serialPort->setFlowControl(QSerialPort::NoFlowControl);     //执行，无流控
        }
        //7.打开串口
        if(serialPort->open(QIODevice::ReadWrite))
        {
            qDebug() << "serial open success";
            ui->comboBox_databit->setEnabled(false);    //成功打开串口，这些按钮就失效
            ui->comboBox_fluidCon->setEnabled(false);
            ui->comboBox_jiaoyan->setEnabled(false);
            ui->comboBox_stopbit->setEnabled(false);
            ui->comboBox_boautrate->setEnabled(false);
            ui->comboBox_serialnum->setEnabled(false);
            ui->btncloseorOpen->setText("关闭串口");
            ui->btnSendContex->setEnabled(true);
            ui->checkBoxSendInTime->setEnabled(true);  //成功打开串口，定时发送按钮生效
            ui->checkBoxrevTime->setEnabled(true);  //成功打开串口，接收时间按钮生效


        }
        else
        {
            qDebug() << "error";
            QMessageBox msgBox;         //弹窗
            msgBox.setWindowTitle("打开串口错误");
            msgBox.setText("打开失败，串口可能被占用或已拔出");
            msgBox.exec();
        }

    }
    else
    {
        serialPort->close();
        ui->btncloseorOpen->setText("打开串口");
        ui->comboBox_databit->setEnabled(true);    //没有打开串口，这些按钮都是生效的
        ui->comboBox_fluidCon->setEnabled(true);
        ui->comboBox_jiaoyan->setEnabled(true);
        ui->comboBox_stopbit->setEnabled(true);
        ui->comboBox_boautrate->setEnabled(true);
        ui->comboBox_serialnum->setEnabled(true);
        //serialStatus = false;
        ui->btnSendContex->setEnabled(false);      //没有打开串口，发送按钮失效
        ui->checkBoxSendInTime->setEnabled(false);  //打开串口失败，定时发送按钮失效
        ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);      //设置复选框为未选中状态
        timer->stop();
        ui->lineEditTimeeach->setEnabled(true);
        ui->lineEditSendContex->setEnabled(true);

    }
}

//发送数据
void Widget::on_btnSendContex_clicked()
{
    int writeCnt = 0;
    const char* sendData = ui->lineEditSendContex->text().toLocal8Bit().constData();    //把发送文本转换为C字符串指针
    if(ui->checkBHexSend->isChecked())      //判断按键是否被按下
    {
        QString tmp = ui->lineEditSendContex->text().toLocal8Bit().constData();
        //判断是否是偶数位，16进制是两位
        QByteArray tmpArray = tmp.toLocal8Bit();
        if(tmpArray.size() % 2 != 0)
        {
            ui->labelSendStatus->setText("Error Input");
        }
        //判断是否符合16进制的表达
        for(char c : tmpArray)      //定义一个c，遍历tmpArray数组
        {
            if(!std::isxdigit(c))   //判断每一位是不是十六进制
            {
                ui->labelSendStatus->setText("Error Input");
                return;
            }
        }
        //转换成16进制发送，用户输入1，变成1，不会变成字符1，ASCII码
        QByteArray arraySend = QByteArray::fromHex(tmpArray);    //发送16进制

        writeCnt = serialPort->write(arraySend);     //返回实际写入的字节数

    }
    else
    {
        writeCnt = serialPort->write(sendData);     //返回实际写入的字节数
    }


    if(writeCnt == -1)
    {
        ui->labelSendStatus->setText("Send Error!");       //返回字节数失败，表示发送错误
    }
    else
    {
        writeCntTotal += writeCnt;          //写入成功，将字节数累加到writeCntTotal变量上
        qDebug() << "SendOK" << sendData;       //输出SendOK和sendData里面的内容

        ui->labelSendStatus->setText("Send OK!");       //把发送状态改为Send OK
        ui->labelSendcnt->setNum(writeCntTotal);

        if(strcmp(sendData,SendBack.toStdString().c_str()) != 0)    //比较sendData和上一次输出的数据是否相同
        {
            ui->textEditRecord->append(sendData);       //不同则在textEditRecord里追加数据
            SendBack = QString::fromUtf8(sendData);               //将数据转成QString类型，以便下次使用
        }

    }

}

//读取发送的数据
void Widget::on_SerialData_readyToRead()
{
    QString revMessage = serialPort->readAll();     //读取数据存于revMessage
    if(revMessage != NULL)          //检查指针 revMessage 是否为非空指针
    {
        if(ui->checkBoxHexDisplay->isChecked())
        {
            QByteArray tmpHexString = revMessage.toUtf8().toHex();
            //原来控件上的内容，hex
            QString tmpStringHex = ui->textEditRev->toPlainText();  //因为勾选了，读出来就是Hex
            tmpHexString = tmpStringHex.toUtf8() + tmpHexString;    //把读出的就的hex和新收到的数据转成hex进行拼接
            ui->textEditRev->setText(QString::fromUtf8(tmpHexString));  //重新显示在控件上
        }
        else
        {
            if(ui->checkBoxrevTime->isChecked())
            {
                getSysTime();
                QString message = ui->lineEditSendContex->text() + " " + "【"+MyTime+"】";
                ui->textEditRev->append(message);
            }
            else
            {
                ui->textEditRev->append(revMessage);            //将收到的内容追加到textEditRev文本框中

            }
        }
        readCntTotal += revMessage.size();
        ui->labelRevcnt->setNum(readCntTotal);          //计算接收到的字节数
    }
}


//自动发送
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
    //    qDebug() <<"checkBsendIntime" << checked;
    if(checked)         //检测复选框是否被选中
    {
        ui->lineEditTimeeach->setEnabled(false);         //定时发送开始，定时文本无效
        ui->lineEditTimeeach->setEnabled(false);         //定时发送开始，发送文本无效
        timer->start(1000);                         //启动定时器
        timer->start(ui->lineEditTimeeach->text().toInt());     //允许用户修改时间间隔
        //on_btnSendContex_clicked();
    }
    else
    {
        timer->stop();          //停止定时器
        ui->lineEditTimeeach->setEnabled(true);         //定时器停止后，定时文本变有效
        ui->lineEditSendContex->setEnabled(true);       //定时器停止后，发送文本变有效
    }
}

//清空接收
void Widget::on_btnrevClear_clicked()
{
    ui->textEditRev->setText("");       //清空接收内容
}

//保存接收内容
void Widget::on_btnrevSave_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                    "L:/QTproject/QT/serialData.txt",
                                                    tr("Text (*.txt)"));       //弹出文件选择框，保存文件
    if(fileName != NULL)
    {
        QFile file(fileName);       //创建一个 QFile 对象，用于操作文件
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            return;       //打开文件失败，则直接返回
        }

        QTextStream out(&file);     //创建一个QTextStream 对象，用于将数据写入文件
        out <<ui->textEditRev->toPlainText();       //获取文本内容，输出到流out
        file.close();       //关闭文件

    }
}

//更新串口调试助手时间
void Widget::time_reflash()
{
    getSysTime();
    ui->labelCurrentTime->setText(MyTime);
}
//获取系统时间
void Widget::getSysTime()
{
    QDateTime currentTime = QDateTime::currentDateTime();   //创建一个currentTime对象，返回当前系统时间

    QDate date = currentTime.date();        //返回一个日期对象date
    int year = date.year();             //获取年份，存储在year变量中
    int month = date.month();           //获取月份，存储在month变量中
    int day = date.day();               //获取日，存储在day变量中

    QTime time = currentTime.time();        //创建一个time对象，返回时间
    int hour = time.hour();             //获取时，存储在hour变量中
    int minute = time.minute();         //获取时，存储在minute变量中
    int second = time.second();         //获取时，存储在second变量中

    MyTime = QString("%1-%2-%3 %4:%5:%6")
            .arg(year,2,10,QChar('0'))
            .arg(month,2,10,QChar('0'))
            .arg(day,2,10,QChar('0'))
            .arg(hour,2,10,QChar('0'))
            .arg(minute,2,10,QChar('0'))
            .arg(second,2,10,QChar('0'));
}


//Hex显示
void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
    if(checked)     //如果打勾
    {
        //1.读取textEdit内容
        QString tmp = ui->textEditRev->toPlainText();
        //2.转换成hex
        QByteArray qtmp = tmp.toUtf8();    //因为QSrting没有把小写字母a转化成61的能力，QByteArray有，所以用QByteArray
        qtmp = qtmp.toHex();
        //3.显示
        QString lastShow;
        tmp = QString::fromUtf8(qtmp);
        for(int i = 0; i<tmp.size();i+=2)
        {
            lastShow += tmp.mid(i,2)+ " ";

        }

        ui->textEditRev->setText(lastShow.toUpper());
    }
    else
    {
        //1.读取textEdit内容，hex
        QString tmpHexString = ui->textEditRev->toPlainText();
        //2.将 QString 转换为 QByteArray
        QByteArray tmpHexQBytearray = tmpHexString.toUtf8();
        //3.将十六进制字符串转换为字节数组
        QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQBytearray);
        //4.显示
        ui->textEditRev->setText(QString::fromUtf8(tmpQByteString));
    }
}
